/**
 * Marcelo A Nagatomo
 * RA 062689
 * Atividade 2.1 - 14-09-2009
 */


/***************************************************************************/
/****   CLIENT    **********************************************************/
/***************************************************************************/


#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#define TRUE 1
#define FALSE 0
#define MAXLINE 1024
#define CLOSE "stop"

/**
 * Set this constant to test the differents steps of program.
 */
#define DEBUG TRUE
//#define DEBUG FALSE

/**
 * Get a string with max size: MAXLINE
 */
char* getString(){
	char *str; 
	char c = '\0';
	int i = 0;
	
	str = (char*) malloc(sizeof(char)*MAXLINE);
	do {
		c = getchar();
		if(c != '\n' && i < MAXLINE) {
			str[i] = c;	
			i++;
		}
		
	} while(c != '\n');
	str[i] = '\0';
		
	return str;
}



/**
 * Create the socket. 
 */
int Socket (int family, int type, int flags)	{
	int sockfd;
	
	if ((sockfd = socket(family, type, flags)) < 0) {
		perror("*** ERROR: an error occur while creating a client socket. ***\n");
		exit(1);

	} else
		return sockfd;
}


/**
 * Convert the source string in struct family AF_INET
 */	
void InetPton (int af, const char *src, void *dst) {

	if (inet_pton(af, src, dst) <= 0) {
		perror("*** ERROR: inet_pton error. ***\n");
		exit(1);
	}
	return;
}

	
/**
 * Start connection with server
 */	
void Connect (int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen){
	
	if (connect(sockfd, serv_addr, addrlen) < 0) {
		perror("*** ERROR: connect error. ***\n");
		exit(1);
	}
	return;
}

/**
 * Returns the IP address of this host.
 */
char* getMyIp(){
	char name[80]; /*store my hostname*/
	struct hostent * hostent_ptr;
	int ret;
	
	
	if((ret = gethostname (name, 80)) < 0) {
		perror("*** ERROR: an error occur while getting hostname. ***\n");
		exit(1);
	}
	
	hostent_ptr = gethostbyname(name);
	if(hostent_ptr == NULL) {
		perror("*** ERROR: an error occur while gettin IP. ***\n");
		exit(1);
	}
	
	// h_addr_list contains IPs of this host in network byte order
	// get the first IP
	in_addr_t myIp = ((struct in_addr *)hostent_ptr->h_addr_list[0])->s_addr; 
	
	struct in_addr temp;
	temp.s_addr = myIp;
		
	return inet_ntoa(temp);
}


/**
 * Get socketInfo.
 * Return:
 * 		char* - "ip:port"
 */
char *getClientInfo(int s, struct sockaddr_in *name){
	char *str;// = (char *)malloc(20*sizeof(char));
	
	socklen_t name_len = sizeof(name);
	if (getsockname(s, (struct sockaddr *) name, &name_len) >= 0){
		// get Socket info
		char port[10];		
		char* strIp = getMyIp();
		sprintf(port,"%d",(int) ntohs(name->sin_port));
		
		// concatane the strings
		int size = strlen(port)+strlen(strIp)+2;
		str = (char *)malloc(size);
		strcat(str,strIp);
		strcat(str,":");
		strcat(str,port);
		str[size] = '\0';
									
	} else {
		perror("*** ERROR: getSockInfo() error. ***\n");
		exit(1);

	}
		
	return str;
}

/**
 * Split the str in 3 tokens
 * Return:
 * 		{command, strIp, strPort}
 */
char** split(char* str){
	
	char** arr = malloc(3*sizeof(char*));
	arr[0] = strtok(str,":");		// scan looking for tokens of ':'
	arr[1] = strtok(NULL,":");		// nextToken();
	arr[2] = strtok(NULL,":");		// nextToken();
	
	return arr;
}


/**
 * Print outputs
 */
void HandleReceiveMsg(char *msg, char* clientInfo){
	char ** arr = split(clientInfo);
	printf("\n> Client IP: [%s]\n",arr[1]);
	printf("> Client Port: [%s]\n",arr[2]);
	printf("> Command Sended: [%s]\n",arr[0]);
	
	arr = split(msg);
	printf("\n> Server IP: [%s]\n",arr[1]);
	printf("> Server Port: [%s]\n",arr[2]);
	printf("> Command Received: [%s]\n\n",arr[0]);
}

/**
 * 	TCP Client.
 * 
 * 	Use:
 * 		./client IP_SERVER PORT
 *
 *	Description:
 *  -lê uma cadeia de caracteres do teclado (entrada padrão) e a envia ao servidor
 * 	-recebe um fluxo de dados do servidor, contendo a mesma cadeia de caracteres que ele havia enviado
 * 	-exibe no vídeo (saída padrão) a cadeia recebida
 */
int main(int argc, char **argv) {
	
	int sockfd, port;
	char *ipServer;
	struct sockaddr_in servaddr;
	
	// InputError handling;
	if (argc != 3){
		char error[MAXLINE + 1];
		strcpy(error, "*** Use: ");
		strcat(error, argv[0]);
		strcat(error, " <IP_SERVER> <PORT>\n\n");
		perror(error);
		exit(1);
	
	} else {
		ipServer = argv[1];
		port = atoi(argv[2]);

	}
	
	bzero(&servaddr, sizeof(servaddr));		//	alocate memory with '0's
	servaddr.sin_family = AF_INET;			// 	set format address
	servaddr.sin_addr.s_addr = inet_addr(ipServer);   /* Server IP address */
	servaddr.sin_port   = htons(port);		//	set port

	// Set client fields and create the conection
	sockfd = Socket(AF_INET, SOCK_STREAM, 0);
	InetPton(AF_INET, ipServer, &servaddr.sin_addr);
	Connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
	
	// get socket info
	char* sockInfo = getClientInfo(sockfd, &servaddr);
	
	// Send and receive messages with server
	int stop=0, n=0, bytes=0, sizeBuffer=0;
	char recvline[MAXLINE + 1];
	char *buffer;
	
	// get string command
	printf("\n> Enter with a command: ");
	buffer = getString();
	strcat(buffer, ":");
	strcat(buffer, sockInfo);
	sizeBuffer = strlen(buffer);
	stop = strcmp(buffer, CLOSE);
	
	if(sizeBuffer > 0 && stop != 0){
		// Send message to server
		bytes = send(sockfd, buffer, sizeBuffer, 0);
		
		printf("\n> Waiting that thread wake up...\n");
				
		// Receive message of server
		n = read(sockfd, recvline, MAXLINE);
		recvline[n] = '\0';
		
		printf("\t> DEBUG_REC: [%s]\n",recvline);
		
		if (n > 0) {
			HandleReceiveMsg(recvline, buffer);

		// ReceiveError Handling	
		} else {
			perror("*** ERROR: receive error. ***\n");
			exit(1);
			
		}
	}
	
	// SendError Handling
	if(bytes == -1){
		perror("*** ERROR: send error. ***\n");
		exit(1);
	}

	exit(0);
}



/**
 * Marcelo A Nagatomo
 * RA 062689
 * Atividade 2.1 - 14-09-2009
 */


/***************************************************************************/
/****   SERVER    **********************************************************/
/***************************************************************************/




#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <time.h>
#include <unistd.h>

#define TRUE 1
#define FALSE 0
#define MAXLINE 1024
#define LISTENQ 10

/**
 * Set this constant to test the differents steps of program.
 */
#define DEBUG TRUE
//#define DEBUG FALSE


/**
 * Create the socket. 
 */
int Socket (int family, int type, int flags)	{
	int sockfd;
	
	if ((sockfd = socket(family, type, flags)) < 0) {
		perror("*** ERROR: an error occur while creating a client socket. ***\n");
		exit(1);

	} else
		return sockfd;
}

/** 
 * Assign a IP address at socket door created.
 */
void Bind (int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen){
	
   if (bind(sockfd, serv_addr, addrlen) < 0) {
      perror("*** ERROR: bind error. ***\n");
      exit(1);
   }
   return;
}


/**
 * Marks the socket referred to by 'listenfd' as a passive socket, that is, as a socket that will
 * be used to accept incoming connection requests using accept.
 */
void Listen (int sockfd, int backlog){

	if (listen(sockfd, backlog) < 0) {
		perror("*** ERROR: an error occur while creating a listener. ***\n");
		exit(1);
	}
	return;
}

/**
 * Get data and remove first connection of stack.
 */
int Accept(int sockfd, struct sockaddr *cliaddr, socklen_t *socklen){
	int connfd;
	if ((connfd = accept(sockfd, cliaddr, socklen)) < 0) {
         perror("accept");
         exit(1);
	}
	return connfd;
}

/**
 *  Creates a new process by duplicating the calling process.
 */
pid_t Fork(){
	pid_t processID;
	if ((processID = fork()) < 0){
	    perror("*** ERROR: an error occur while fork(). ***\n");
		exit(1);
	}
	return processID;
}

/**
 * Split the str in 3 tokens
 * Return:
 * 		{command, strIp, strPort}
 */
char** split(char* str){
	
	char** arr = malloc(3*sizeof(char*));
	arr[0] = strtok(str,":");		// scan looking for tokens of ':'
	arr[1] = strtok(NULL,":");		// nextToken();
	arr[2] = strtok(NULL,":");		// nextToken();
	
	return arr;
}

/**
 * Returns the IP address of this host.
 */
char* getMyIp(){
	char name[80]; /*store my hostname*/
	struct hostent * hostent_ptr;
	int ret;
	
	
	if((ret = gethostname (name, 80)) < 0) {
		perror("*** ERROR: an error occur while getting hostname. ***\n");
		exit(1);
	}
	
	hostent_ptr = gethostbyname(name);
	if(hostent_ptr == NULL) {
		perror("*** ERROR: an error occur while gettin IP. ***\n");
		exit(1);
	}
	
	// h_addr_list contains IPs of this host in network byte order
	// get the first IP
	in_addr_t myIp = ((struct in_addr *)hostent_ptr->h_addr_list[0])->s_addr; 
	
	struct in_addr temp;
	temp.s_addr = myIp;
		
	return inet_ntoa(temp);
}

/**
 * Get server Info.
 * Return:
 * 		char* - "ip:port"
 */
char *getServerInfo(int s, struct sockaddr_in *name){
	char *str;// = (char *)malloc(20*sizeof(char));
	
	socklen_t name_len = sizeof(name);
	if (getsockname(s, (struct sockaddr *) name, &name_len) >= 0){
		// get Socket info
		char port[10];		
		char* strIp = getMyIp();
		sprintf(port,"%d",(int) ntohs(name->sin_port));
		
		// concatane the strings
		int size = strlen(port)+strlen(strIp)+2;
		str = (char *)malloc(size);
		strcat(str,strIp);
		strcat(str,":");
		strcat(str,port);
		str[size] = '\0';
								
	} else {
		perror("*** ERROR: getSockInfo() error. ***\n");
		exit(1);

	}
		
	return str;
}

/**
 * Handle the message received of client.
 * Return:
 * 		- char* - command sended by client.
 */
char* HandleTcpClient(int socket){
	char buffer[MAXLINE+1];
	int size;
	
	size = read(socket, buffer, MAXLINE);
	buffer[size] = '\0';
	
	if(size > 0){
		char* msg = malloc(size+1);
		strcpy(msg, buffer);
	
		// {command, IP, Port}
		char** arr = split(msg);
		
		printf("\n> Client IP: [%s]\n",arr[1]);
		printf("> Client Port: [%s]\n",arr[2]);
		printf("> Command: [%s]\n",arr[0]);
		printf("> Output:\n\n");
		system(arr[0]);
		printf("\n");
	
		return arr[0];
	} else {
		perror("*** ERROR: an error occur receive message. ***\n");
		exit(1);
		
	}
	
}



/**
 * 	TCP Server.
 * 
 * 	Use:
 * 		./server PORT
 *
 *	Description:
 *  - recebe uma cadeia de caracteres enviada pelo cliente
 * 	- reenvia esta cadeia ao cliente
 * 	- executa esta cadeia (que na verdade, deve ser um comando qualquer do Unix)
 */
int main (int argc, char **argv) {
	pid_t pid;
	int port, serverSock, clientSock;
	struct sockaddr_in servaddr;

	// InputError handling;
	if (argc != 2){
		char error[MAXLINE + 1];
		strcpy(error, "*** Use: ");
		strcat(error, argv[0]);
		strcat(error, " <PORT>\n\n");
		perror(error);
		exit(1);
	
	} else {
		port = atoi(argv[1]);

	}
	
	// initialize socket
	bzero(&servaddr, sizeof(servaddr));				// allocates the memory with '0'
	servaddr.sin_family      = AF_INET; 			// set Internet family
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 	// set IP address
	servaddr.sin_port        = htons(port);   		// set port
	
	// create server socket
	serverSock = Socket(AF_INET, SOCK_STREAM, 0);
	Bind(serverSock, (struct sockaddr *)&servaddr, sizeof(servaddr));
	Listen(serverSock, LISTENQ);
	
	char* sockInfo = getServerInfo(serverSock, &servaddr);
		
	while(1){
		// wait a client
		clientSock = Accept(serverSock, (struct sockaddr *) NULL, NULL);
		
		// fork
		if ((pid = Fork()) == 0){
			close(serverSock);
			
			// handle tcp client'
			char* command = HandleTcpClient(clientSock);
			
			printf("> Sleeping thread and waiting connections...\n\n",pid);
			sleep(10);
			
			// mount answer msg
			char* msg = malloc(MAXLINE);
			strcpy(msg, command);
			strcat(msg,":");
			strcat(msg,sockInfo);
			int size = strlen(msg);
		
			// send message
			int bytes = send(clientSock, msg, size, 0);
			
			// SendError Handling
			if(bytes == -1){
				perror("*** ERROR: send error. ***\n");
				exit(1);
			}
			
			close(clientSock);
			exit(0);
		}
		
		close(clientSock);
	}
			
	return(0);
}



